package com.cq.hd.member.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cq.hd.common.constant.Constant;
import com.cq.hd.common.constant.RedisKeyConstant;
import com.cq.hd.common.entity.UserInfo;
import com.cq.hd.common.enums.biz.SmsTypeEnum;
import com.cq.hd.common.pagination.Page;
import com.cq.hd.common.response.Throw;
import com.cq.hd.common.utils.BeanUtils;
import com.cq.hd.common.utils.NoUtils;
import com.cq.hd.common.utils.RedisUtil;
import com.cq.hd.common.utils.StringUtils;
import com.cq.hd.member.api.dto.*;
import com.cq.hd.member.api.vo.AppUserPageVo;
import com.cq.hd.member.api.vo.AppUserVo;
import com.cq.hd.member.biz.SmsBiz;
import com.cq.hd.member.config.LockUtils;
import com.cq.hd.member.mapper.*;
import com.cq.hd.member.po.TbAppUserPo;
import com.cq.hd.member.po.TbCommissionBillPo;
import com.cq.hd.member.po.TbMerchantAmtBillPo;
import com.cq.hd.member.service.TbAppUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cq.hd.member.service.TbAutoWithdrawalRecordService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * app用户表 服务实现类
 * </p>
 *
 * @author mYunYu
 * @since 2023-11-21
 */
@Slf4j
@Service
public class TbAppUserServiceImpl extends ServiceImpl<TbAppUserMapper, TbAppUserPo> implements TbAppUserService {

    @Autowired
    private TbMerchantMapper merchantMapper;

    @Autowired
    private TbBusinessAgentMapper businessAgentMapper;

    @Autowired
    private PlatformTransactionManager transactionManager;

    @Autowired
    private TbMerchantAmtBillMapper merchantAmtBillMapper;

    @Autowired
    private TbCommissionBillMapper commissionBillMapper;

    @Autowired
    private TbAutoWithdrawalRecordService autoWithdrawalRecordService;

    @Autowired
    private SmsBiz smsBiz;

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public Page<AppUserPageVo> pageAppUser(AppUserPageDto appUserPageDto) {
        String startRegisterTime = appUserPageDto.getStartRegisterTime();
        String endRegisterTime = appUserPageDto.getEndRegisterTime();
        String startLastLoginTime = appUserPageDto.getStartLastLoginTime();
        String endLastLoginTime = appUserPageDto.getEndLastLoginTime();
        if (!StringUtils.isBlank(startRegisterTime) && startRegisterTime.length() != 19) {
            Throw.isBusinessException("日期格式错误");
        }
        if (!StringUtils.isBlank(endRegisterTime) && endRegisterTime.length() != 19) {
            Throw.isBusinessException("日期格式错误");
        }

        if (!StringUtils.isBlank(startLastLoginTime) && startLastLoginTime.length() != 19) {
            Throw.isBusinessException("日期格式错误");
        }
        if (!StringUtils.isBlank(endLastLoginTime) && endLastLoginTime.length() != 19) {
            Throw.isBusinessException("日期格式错误");
        }

        PageHelper.startPage(appUserPageDto.getPageNum(), appUserPageDto.getPageSize());
        List<AppUserPageVo> appUserPageVos = baseMapper.listAppUserByDto(appUserPageDto);
        PageInfo<AppUserPageVo> pageInfo = new PageInfo<>(appUserPageVos);
        return Page.newPageWithAllFields(pageInfo.getList(), pageInfo.getPageNum(), pageInfo.getPageSize(), pageInfo.getTotal(), pageInfo.getPages());
    }

    @Override
    public AppUserVo getByMobile(String mobile) {
        List<TbAppUserPo> appUserPos = baseMapper.selectList(new QueryWrapper<TbAppUserPo>().eq("del_state", 0)
                .eq("mobile", mobile));
        if (!CollectionUtils.isEmpty(appUserPos)) {
            AppUserVo appUserVo = new AppUserVo();
            BeanUtils.copyProperties(appUserPos.get(0), appUserVo);
            return appUserVo;
        }
        return null;
    }

    @Override
    public AppUserVo register(LoginDto loginDto) {
        TbAppUserPo tbAppUserPo = new TbAppUserPo();
        tbAppUserPo.setMobile(loginDto.getMobile());
        tbAppUserPo.setOpenid(loginDto.getOpenId());
        tbAppUserPo.setUnionid(loginDto.getUnionId());
        tbAppUserPo.setUserName(loginDto.getMobile());
        tbAppUserPo.setNickName(loginDto.getNickName());
        tbAppUserPo.setAvatar(loginDto.getAvatar());
        tbAppUserPo.setCreateTime(LocalDateTime.now());
        tbAppUserPo.setRegisterIp(loginDto.getIpAddr());
        tbAppUserPo.setRegisterTime(LocalDateTime.now());
        tbAppUserPo.setLastLoginIp(loginDto.getIpAddr());
        tbAppUserPo.setLastLoginTime(LocalDateTime.now());
        tbAppUserPo.setInviteCode(NoUtils.getUserInviteCode());
        int insert = baseMapper.insert(tbAppUserPo);
        if (insert == 0) {
            Throw.isBusinessException("用户注册失败");
        }

        TbAppUserPo appUserPo = baseMapper.selectById(tbAppUserPo.getId());
        AppUserVo appUserVo = new AppUserVo();
        BeanUtils.copyProperties(appUserPo, appUserVo);

        return appUserVo;
    }

    @Override
    public AppUserVo getAppUserById(long id) {
        TbAppUserPo tbAppUserPo = baseMapper.selectById(id);
        if (tbAppUserPo != null) {
            AppUserVo appUserVo = new AppUserVo();
            BeanUtils.copyProperties(tbAppUserPo, appUserVo);
            return appUserVo;
        }
        return null;
    }

    @Override
    public AppUserVo getByOpenId(String openId) {
        return baseMapper.getByOpenId(openId);
    }

    @Override
    public List<AppUserVo> listByUserIds(List<Long> userIds) {
        return baseMapper.listByUserIds(userIds);
    }

    @Override
    public Integer getNewCountByDate(String startTime, String endTime) {
        return baseMapper.selectCount(new QueryWrapper<TbAppUserPo>().eq("del_state", 0).ge("register_time", startTime).le("register_time", endTime));
    }

    @Override
    public Boolean addCommissionAmt(Long userId, BigDecimal commissionAmt) {
        return baseMapper.addCommissionAmt(userId, commissionAmt);
    }

    @Override
    public Boolean subCommissionAmt(Long userId, BigDecimal commissionAmt) {
        return baseMapper.subCommissionAmt(userId, commissionAmt);
    }

    @Override
    public Boolean updateOrderSettleAmt(OrderSettleUpdateDto orderSettleUpdateDto) {
        log.info("updateOrderSettleAmt: {}", orderSettleUpdateDto);

        Long orderId = orderSettleUpdateDto.getOrderId();
        Long agentId = orderSettleUpdateDto.getAgentId();
        BigDecimal commissionAmt = orderSettleUpdateDto.getCommissionAmt();
        UpdateBusinessAgentOrderDto updateBusinessAgentOrderDto = orderSettleUpdateDto.getUpdateBusinessAgentOrderDto();
        // 二级经纪人
        Long agent2Id = orderSettleUpdateDto.getAgent2Id();
        BigDecimal subCommissionAmt = orderSettleUpdateDto.getSubCommissionAmt();
        UpdateSubAgentOrderDto updateSubAgentOrderDto = orderSettleUpdateDto.getUpdateSubAgentOrderDto();
        List<MerchantAmtAddDto> merchantAmtAdds = orderSettleUpdateDto.getMerchantAmtAdds();
        List<MerchantAmtBillSaveDto> merchantAmtBillSaves = orderSettleUpdateDto.getMerchantAmtBillSaves();
        List<CommissionBillSaveDto> commissionBillSaves = orderSettleUpdateDto.getCommissionBillSaves();

        TransactionStatus transaction = transactionManager.getTransaction(new DefaultTransactionAttribute());

        try {
            // 1、更新商户本金，商户补贴
            if (!CollectionUtils.isEmpty(merchantAmtAdds)) {
                for (MerchantAmtAddDto merchantAmtAdd : merchantAmtAdds) {
                    if (merchantAmtAdd.getSubsidyAmt().compareTo(BigDecimal.ZERO) <= 0 && merchantAmtAdd.getBalanceAmt().compareTo(BigDecimal.ZERO) <= 0) {
                        continue;
                    }

                    Boolean merchantAmtAddDtoState = merchantMapper.merchantAmtAddDto(merchantAmtAdd);
                    if (merchantAmtAddDtoState == null || !merchantAmtAddDtoState) {
                        log.error("更新商户本金/商户补贴失败，orderId：{}", orderId);
                        Throw.isBusinessException("更新商户本金/商户补贴失败");
                    }
                }
            }

            // 2、添加商户资金流水
            if (!CollectionUtils.isEmpty(merchantAmtBillSaves)) {
                for (MerchantAmtBillSaveDto merchantAmtBillSaveDto : merchantAmtBillSaves) {
                    if (merchantAmtBillSaveDto.getTradeAmt().compareTo(BigDecimal.ZERO) <= 0) {
                        continue;
                    }

                    TbMerchantAmtBillPo tbMerchantAmtBillPo = new TbMerchantAmtBillPo();
                    BeanUtils.copyProperties(merchantAmtBillSaveDto, tbMerchantAmtBillPo);
                    int insert = merchantAmtBillMapper.insert(tbMerchantAmtBillPo);
                    if (insert == 0) {
                        log.error("添加商户资金流水数据失败，orderId：{}", orderId);
                        Throw.isBusinessException("添加商户资金流水数据失败");
                    }
                }
            }

            // 3、添加经纪人佣金流水
            if (!CollectionUtils.isEmpty(commissionBillSaves)) {
                for (CommissionBillSaveDto commissionBillSave : commissionBillSaves) {
                    TbCommissionBillPo tbCommissionBillPo = new TbCommissionBillPo();
                    BeanUtils.copyProperties(commissionBillSave, tbCommissionBillPo);
                    tbCommissionBillPo.setCreateTime(LocalDateTime.now());
                    tbCommissionBillPo.setUpdateTime(LocalDateTime.now());
                    int insert = commissionBillMapper.insert(tbCommissionBillPo);
                    if (insert == 0) {
                        log.error("添加经纪人佣金流水失败，orderId：{}", orderId);
                        Throw.isBusinessException("添加经纪人佣金流水失败");
                    }
                }
            }

            // 一级经纪人佣金
            if (agentId != null && agentId > 0 && commissionAmt != null && commissionAmt.compareTo(BigDecimal.ZERO) > 0
                    && updateBusinessAgentOrderDto != null) {
                // 4、更新经纪人佣金
                Boolean addCommissionAmtState = baseMapper.addCommissionAmt(agentId, commissionAmt);
                if (addCommissionAmtState == null || !addCommissionAmtState) {
                    log.error("更新经纪人佣金失败，orderId：{}", orderId);
                    Throw.isBusinessException("更新经纪人佣金失败");
                }

                // 5、统计商家与经纪人的累计结算分销佣金
                Boolean updateBusinessAgentOrderState = businessAgentMapper.updateBusinessAgentOrder(updateBusinessAgentOrderDto);
                if (updateBusinessAgentOrderState == null || !updateBusinessAgentOrderState) {
                    log.error("更新商家与经纪人的累计结算分销佣金失败，orderId：{}", orderId);
                    Throw.isBusinessException("更新商家与经纪人的累计结算分销佣金失败");
                }
            }

            // 二级经纪人佣金
            if (agent2Id != null && agent2Id > 0 && subCommissionAmt != null && subCommissionAmt.compareTo(BigDecimal.ZERO) > 0
                    && updateSubAgentOrderDto != null) {
                // 6、更新二级经纪人佣金
                Boolean addCommissionAmtState = baseMapper.addCommissionAmt(agent2Id, subCommissionAmt);
                if (addCommissionAmtState == null || !addCommissionAmtState) {
                    log.error("更新二级经纪人佣金失败，orderId：{}", orderId);
                    Throw.isBusinessException("更新二级经纪人佣金失败");
                }

                // 7、统计二级经纪人与一级经纪人的累计结算分销佣金
                Boolean updateSubAgentOrderState = businessAgentMapper.updateSubAgentOrder(updateSubAgentOrderDto);
                if (updateSubAgentOrderState == null || !updateSubAgentOrderState) {
                    log.error("更新二级与经纪人的累计结算分销佣金失败，orderId：{}", orderId);
                    Throw.isBusinessException("更新二级与经纪人的累计结算分销佣金失败");
                }
            }

            // 8、自动提现记录
            autoWithdrawalRecordService.addRecords(orderSettleUpdateDto.getAutoWithdrawalRecords());

            transactionManager.commit(transaction);
        } catch (Exception e) {
            //回滚事务
            transactionManager.rollback(transaction);
            log.error("<更新订单结算金额>事务异常回滚", e);
            return false;
        }

        return true;
    }

    @Override
    public Boolean updateUnionidById(Long id, String unionid) {
        return baseMapper.updateUnionidById(id, unionid);
    }

    @Override
    public AppUserVo getByUnionid(String unionid) {
        return baseMapper.getByUnionid(unionid);
    }

    @Override
    public Boolean updatePwd(AppUserPwdUpdateDto appUserPwdUpdateDto) {
        String originPwd = appUserPwdUpdateDto.getOriginPwd();
        String newPwd = appUserPwdUpdateDto.getNewPwd();
        String confirmPwd = appUserPwdUpdateDto.getConfirmPwd();
        String smsCode = appUserPwdUpdateDto.getSmsCode();

        if (StringUtils.isBlank(smsCode)) {
            Throw.isBusinessException("请输入验证码");
        }

        if (StringUtils.isBlank(newPwd)) {
            Throw.isBusinessException("请输入新密码");
        }

        if (StringUtils.isBlank(confirmPwd)) {
            Throw.isBusinessException("请输入确认密码");
        }

        if (!newPwd.equals(confirmPwd)) {
            Throw.isBusinessException("两次密码输入不一致");
        }

        TbAppUserPo tbAppUserPo = baseMapper.selectById(appUserPwdUpdateDto.getId());
        if (tbAppUserPo == null) {
            Throw.isBusinessException("未找到用户数据");
        }

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

//        String loginPass = tbAppUserPo.getLoginPass();
//        if (!StringUtils.isBlank(loginPass)) {
//            // 表示非首次设置密码，需要校验原始密码
//            if (StringUtils.isBlank(originPwd)) {
//                Throw.isBusinessException("请输入原始密码");
//            }
//
//            // 校验旧密码是否正确
//            if (!encoder.matches(originPwd, tbAppUserPo.getLoginPass())) {
//                Throw.isBusinessException("原始密码错误");
//            }
//        }

        String mobile = tbAppUserPo.getMobile();

        // 对手机号加锁
        String lockKey = MessageFormat.format(Constant.LOCK_FORMAT, "updatePwd:" + mobile);
        try {
            LockUtils.blockLock(lockKey, Constant.AUTO_UNLOCK_SECOND);

            // 判断短信验证码是否正确
            SmsVerifyDto smsVerifyDto = new SmsVerifyDto();
            smsVerifyDto.setCode(smsCode);
            smsVerifyDto.setMobile(mobile);
            smsVerifyDto.setType(SmsTypeEnum.SMS_UPDATE_APP_USER_LOGIN_PWD.getValue());
            smsBiz.verify(smsVerifyDto).isSuccess();

            tbAppUserPo.setLoginPass(encoder.encode(newPwd));
            tbAppUserPo.setUpdateTime(LocalDateTime.now());
            int update = baseMapper.updateById(tbAppUserPo);
            if (update == 0) {
                Throw.isBusinessException("密码修改失败");
            }

            String userIdRedis = String.valueOf(tbAppUserPo.getId());
            String userInfoRedis = redisUtil.get(String.format(RedisKeyConstant.USER_INFO_KEY, userIdRedis));
            if (!StringUtils.isNullOrEmpty(userInfoRedis)) {
                UserInfo userInfo = JSON.parseObject(userInfoRedis, UserInfo.class);
                userInfo.setPwdSetState(true);

                // 将用户详细信息缓存到Redis
                redisUtil.set(String.format(RedisKeyConstant.USER_INFO_KEY, userIdRedis), JSON.toJSONString(userInfo), Constant.USER_LOGIN_TIMEOUT, TimeUnit.SECONDS);
            }

            return true;
        } finally {
            LockUtils.unlock(lockKey);
        }
    }
}
